package com.yjpark.apps.netcalc;

import com.yjpark.protocols.*;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.StringTokenizer;

import android.app.Activity;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;


public class CalculateNetwork extends Thread {

    protected static BufferedOutputStream mmOutStream; // 출력 스트림
    protected static Socket socket;
    private ReceiverService mReceiverService;
    private SendService mSendService;

    // instances
    DelimFramer delimFramer = null;
    LengthFramer lengthFramer = null;
    TextCodec textCodec = null;
    BinCodec binCodec = null;

	public CalculateNetwork() {
	}
	
	public CalculateNetwork(Socket socket, Handler handler) {
	    // read
		mReceiverService = new ReceiverService(socket, handler);
		
		// write
        mSendService = new SendService();
	}
	
	public CalculateNetwork(Handler handler, String ip, int port) {
        // read
		mReceiverService = new ReceiverService(handler, ip, port);
        mReceiverService.start();
        
        // write
        mSendService = new SendService();
        mSendService.start();
    }
	
    public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		CalculateNetwork.socket = socket;
	}

    public void read() {
    	mReceiverService.run();
    	
    }
    
    class ReceiverService extends Thread {
        private BufferedInputStream mmInStream; // 입력 스트림

        private Handler handler;

        // protocol
        Packet packet = null;

        PacketHeader header = null;

        public ReceiverService(Socket socket, Handler handler) {
            super();
            this.handler = handler;

            try {
                mmInStream = new BufferedInputStream(socket.getInputStream());
                mmOutStream = new BufferedOutputStream(socket.getOutputStream());

                // protocol instance
                delimFramer = new DelimFramer();
                lengthFramer = new LengthFramer();
                textCodec = new TextCodec();
                binCodec = new BinCodec();
            } catch (IOException e1) {
            }
        }
        
        public ReceiverService(Handler handler, String ip, int port) {
            super();
            this.handler = handler;

            try {
                socket = new Socket(ip, port);
                mmInStream = new BufferedInputStream(socket.getInputStream());
                mmOutStream = new BufferedOutputStream(socket.getOutputStream());

                // protocol instance
                delimFramer = new DelimFramer();
                lengthFramer = new LengthFramer();
                textCodec = new TextCodec();
                binCodec = new BinCodec();
            } catch (IOException e1) {
            }
        }

        @Override
        public void run() {
            byte[] deFrameStream = null;
            byte[] leFrameStream = null;
            Packet packet = null;
            PacketHeader header = null;

            try {
                // DelimFramer.next
                deFrameStream = delimFramer.next(mmInStream);
                leFrameStream = deFrameStream.clone();
                
                // TextCodec.decode
                packet = textCodec.decode(deFrameStream);
                header = packet.Header;

                // =============================================== //
                // Binary: M_LOGREQ, M_LOGRES, M_PROFILEREQ, M_PROFILERES            
                Message msg = new Message();
                if( header.getTypeString().equals("M_LOGRES") || header.getTypeString().equals("M_PROFILERES") ) {
                    // binCodec.decode
                    packet = binCodec.decode(leFrameStream);
                    header = packet.Header;
                    
                    String byteData = new String(packet.ByteData, "UTF-8");
//                    System.out.println("[run()]byteData:"+byteData);
                    
                    msg.obj = header.getTypeString()+":"+byteData;
                } else  {
                // Text: M_HELLO, M_BYE, M_CALCREQ, M_CALCRES, M_LOGINREQ, M_LOGINRES, M_JOINREQ, M_JOINRES
                    msg.obj = header.getTypeString()+":"+packet.StringData;
                }
                
                System.out.println("[run()]msg.obj:"+(String) msg.obj);
                
                handler.sendMessage(msg);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void cancel() {
        try {
            socket.close();
        } catch (IOException e) {
        }
    }

    public void write(String out, String msgType) {
        mSendService.write(out, msgType);
    }

    class SendService extends Thread {
        public void write(String out, String msgType) {
        	int msgLength = 0;
        	
        	System.out.println("[write()]out:"+out);
        	System.out.println("[write()]msgType:"+msgType);
        	
            try {
                if (CalculateNetwork.socket != null
                        && CalculateNetwork.socket.isConnected()) {
                    
                	// Binary: M_LOGREQ, M_LOGRES, M_PROFILEREQ, M_PROFILERES
                	if( msgType.equals("M_LOGREQ") || msgType.equals("M_PROFILEREQ") ) {
                		
                		// BinCodec.encode
        				byte[] outBuf = binCodec.encode(new Packet(new PacketHeader(
        						PacketHeader.getValue(msgType), msgLength), new byte[0]));

        				// LengthFramer.framming
        				lengthFramer.framing(outBuf, mmOutStream);
        				
                	} else {
                	// Text: M_HELLO, M_BYE, M_CALCREQ, M_CALCRES, M_LOGINREQ, M_LOGINRES, M_JOINREQ, M_JOINRES
                		
                		// TextCodec.encode
                        byte[] outBuf = textCodec.encode(new Packet(
                                new PacketHeader(PacketHeader.getValue(msgType), msgLength), out));
                        
                        // DelimFramer.framming
                        delimFramer.framing(outBuf, mmOutStream);	
                	}
                }
            } catch (Exception e) {
            }
        }
    }
}
